unit area_trn;

{$mode Delphi}

interface

uses
    Classes, SysUtils, Dialogs, Math, area_pnt;

type

    // Каноническое уравнение прямой
    TDAEquation = record
        arg_a: Real;
        arg_b: Real;
        arg_c: Real;
    end;

    TDATriangle = class
    private
        // Вершины треугольника
        head_f: TDAPoint;
        head_s: TDAPoint;
        head_t: TDAPoint;
        // Биссектрисы треугольника
        bisc_f: TDAPoint;
        bisc_s: TDAPoint;
        bisc_t: TDAPoint;
        // Центр треугольника
        center: TDAPoint;
        // Составление уравнения прямой
        function get_sideq(head_f, head_s: TDAPoint) :TDAEquation;
        // Составление уравнения биссектрисы #1
        function get_biseq(side_f, side_s: TDAEquation; 
                           try_another: Boolean = False) :TDAEquation;
        // Получение точки пересечения прямых
        function get_cross_pnt(ln_f, ln_s: TDAEquation) :TDAPoint;
        // Вычисление угла между прямыми
        function get_line_angl(ln_f, ln_s: TDAEquation) :Real;
    public
        // Конструктор класса
        Constructor init(phead_f, phead_s, phead_t: TDAPoint);
        // Получение координат вершин
    	function get_head_pnt(trn_head_n: Integer) :TDAPoint;
        // Получение координат биссектрисы
        function get_bisc_pnt(trn_bisc_n: Integer) :TDAPoint;
        // Получение координатцентра треугольника
        function get_cent_pnt() :TDAPoint;
        // Получение длины ребер
    	function get_side_len(trn_side_n: Integer) :Real;
        // Получение длины биссектрисы
        function get_bisc_len(trn_bisc_n: Integer) :Real;
        // Получение номера минимальной биссектрисы
        function get_bisc_min() :Integer;
    end;

implementation

const
    PREC_V = -4;

// Составление уравнения прямой
function TDATriangle.get_sideq(head_f, head_s: TDAPoint) :TDAEquation;
var
    sideq_o: TDAEquation;
begin
    with sideq_o do
    begin
        arg_a := head_f.get_rcoord.Y - head_s.get_rcoord.Y;
        arg_b := head_s.get_rcoord.X - head_f.get_rcoord.X;
        arg_c := (head_f.get_rcoord.X - 
                  head_s.get_rcoord.X) * 
                  head_f.get_rcoord.Y + 
                 (head_s.get_rcoord.Y -
                  head_f.get_rcoord.Y) * 
                  head_f.get_rcoord.X;
    end;
    get_sideq := sideq_o;
end;

// Составление уравнения биссектрисы
function TDATriangle.get_biseq(side_f, side_s: TDAEquation;
                               try_another: Boolean = False) :TDAEquation;
var
  cache_a, cache_b: Real;
  biseq_o: TDAEquation;
begin
    cache_a := SQRT(SQR(side_f.arg_a) + SQR(side_f.arg_b));
    cache_b := SQRT(SQR(side_s.arg_a) + SQR(side_s.arg_b));

    if try_another then cache_a := -cache_a;

    with biseq_o do
    begin
      arg_a := side_f.arg_a * cache_b + side_s.arg_a * cache_a;
      arg_b := side_f.arg_b * cache_b + side_s.arg_b * cache_a;
      arg_c := side_f.arg_c * cache_b + side_s.arg_c * cache_a;
    end;

    get_biseq := biseq_o;
end;

// Получение точки пересечения прямых
function TDATriangle.get_cross_pnt(ln_f, ln_s: TDAEquation) :TDAPoint;
var
    cross_pnt_o: TDAPoint;
    coord_x, coord_y: Real;
begin
    with cross_pnt_o do
    begin
        coord_x := -((ln_f.arg_c * ln_s.arg_b - ln_s.arg_c * ln_f.arg_b) /
                     (ln_f.arg_a * ln_s.arg_b - ln_s.arg_a * ln_f.arg_b));

        coord_y := -((ln_f.arg_a * ln_s.arg_c - ln_s.arg_a * ln_f.arg_c) /
                     (ln_f.arg_a * ln_s.arg_b - ln_s.arg_a * ln_f.arg_b));
    end;
    cross_pnt_o := TDAPoint.init(coord_x, coord_y);
    get_cross_pnt := cross_pnt_o;
end;

// Вычисление угла между прямыми
function TDATriangle.get_line_angl(ln_f, ln_s: TDAEquation) :Real;
begin
    get_line_angl := (ln_f.arg_a * ln_s.arg_b - ln_s.arg_a * ln_f.arg_b) / 
                     (ln_f.arg_a * ln_s.arg_a + ln_f.arg_b * ln_s.arg_b);
end;

// Подфункция вычисления длины прямой
function sub_get_side_len(pnt_f, pnt_s: TDAPoint) :Real;
begin
    sub_get_side_len := 
    RoundTo(SQRT(SQR(pnt_s.get_rcoord.X - pnt_f.get_rcoord.X) +
                 SQR(pnt_s.get_rcoord.Y - pnt_f.get_rcoord.Y)), PREC_V);
end;

// Подфункция вычисления длины биссектрисы
function sub_get_bisc_len(side_a, side_b, side_c: Real) :Real;
var
    cache: Real;
begin
    cache := side_a + side_b;
    sub_get_bisc_len := RoundTo(SQRT(side_a * side_b * (cache + side_c) * 
                                    (cache - side_c)) / cache, PREC_V);
end;

// Конструктор класса
Constructor TDATriangle.init(phead_f, phead_s, phead_t: TDAPoint);
var
    // Уравнения ребер
    side_fs, side_st, side_ft: TDAEquation;
    // Уравнения биссектрис
    biseq_f, biseq_s, biseq_t: TDAEquation;
    // Уравнения медиан
    medan_f, medan_s: TDAEquation;
    // Длины биссектрис
    len_t, len_r: Real;
    // Середины ребер
    med_f, med_s: TDAPoint;
begin
    // Вершины треугольника
    head_f := phead_f;
    head_s := phead_s;
    head_t := phead_t;
    
    // Составление уравнений ребер
    side_fs := get_sideq(head_f, head_s);
    side_st := get_sideq(head_s, head_t);
    side_ft := get_sideq(head_f, head_t);

    // Составление уравнений биссектрис
    biseq_f := get_biseq(side_ft, side_fs);
    biseq_s := get_biseq(side_fs, side_st);
    biseq_t := get_biseq(side_ft, side_st);

    // Точки пересечения биссектрис и ребер
    bisc_f := get_cross_pnt(biseq_f, side_st);
    bisc_s := get_cross_pnt(biseq_s, side_ft);
    bisc_t := get_cross_pnt(biseq_t, side_fs);

    // Корректирование уравнения #1
    len_t := Round(sub_get_side_len(head_f, bisc_f));
    len_r := Round(get_bisc_len(0));
    if len_t <> len_r then
    begin
        biseq_f := get_biseq(side_ft, side_fs, True);
        bisc_f := get_cross_pnt(biseq_f, side_st);  
    end;

    // Корректирование уравнения #2
    len_t := Round(sub_get_side_len(head_s, bisc_s));
    len_r := Round(get_bisc_len(1));
    if len_t <> len_r then
    begin
        biseq_s := get_biseq(side_fs, side_st, True);
        bisc_s := get_cross_pnt(biseq_s, side_ft); 
    end;

    // Корректирование уравнения #3
    len_t := Round(sub_get_side_len(head_t, bisc_t));
    len_r := Round(get_bisc_len(2));
    if len_t <> len_r then
    begin
        biseq_t := get_biseq(side_ft, side_st, True);
        bisc_t := get_cross_pnt(biseq_t, side_fs); 
    end;

    // Середины ребер
    med_f := TDAPoint.init((head_s.get_rcoord.X + head_t.get_rcoord.X) / 2, 
                           (head_s.get_rcoord.Y + head_t.get_rcoord.Y) / 2);
    med_s := TDAPoint.init((head_f.get_rcoord.X + head_t.get_rcoord.X) / 2, 
                           (head_f.get_rcoord.Y + head_t.get_rcoord.Y) / 2);
    // Составление уравнений медиан
    medan_f := get_sideq(head_f, med_f);
    medan_s := get_sideq(head_s, med_s);
    // Центр треугольника
    center := get_cross_pnt(medan_f, medan_s);
end;

// Получение координат вершины
function TDATriangle.get_head_pnt(trn_head_n: Integer) :TDAPoint;
begin
    case trn_head_n of
        0:  get_head_pnt := head_f;
        1:  get_head_pnt := head_s;
        2:  get_head_pnt := head_t;
    end;
end;

// Получение координат биссектрисы
function TDATriangle.get_bisc_pnt(trn_bisc_n: Integer) :TDAPoint;
begin
    case trn_bisc_n of
        0:  get_bisc_pnt := bisc_f;
        1:  get_bisc_pnt := bisc_s;
        2:  get_bisc_pnt := bisc_t;
    end;
end;

// Получение координатцентра треугольника
function TDATriangle.get_cent_pnt() :TDAPoint;
begin
    get_cent_pnt := center;
end;

// Получение длины ребер
function TDATriangle.get_side_len(trn_side_n: Integer) :Real;
begin
    case trn_side_n of
        0:  get_side_len := sub_get_side_len(head_f, head_s);
        1:  get_side_len := sub_get_side_len(head_s, head_t);
        2:  get_side_len := sub_get_side_len(head_f, head_t);
    end;
end;

// Получение длины биссектрисы
function TDATriangle.get_bisc_len(trn_bisc_n: Integer) :Real;
begin
    case trn_bisc_n of
        0:  get_bisc_len := sub_get_bisc_len(get_side_len(0), 
                            get_side_len(2), get_side_len(1));
        1:  get_bisc_len := sub_get_bisc_len(get_side_len(0), 
                            get_side_len(1), get_side_len(2));
        2:  get_bisc_len := sub_get_bisc_len(get_side_len(1), 
                            get_side_len(2), get_side_len(0));
    end;
end;

// Подфункция вычисления минимального числа
function sub_get_min(val_a, val_b, val_c: Real) :Integer;
var
    min_n: Integer;
begin
    min_n := 0;

    if val_b < val_a then
    begin
        val_a := val_b;
        min_n := 1;
    end;

    if val_c < val_a then
        min_n := 2;

    sub_get_min := min_n;
end;

// Подфункция вычисления максимального числа
function sub_get_max(val_a, val_b, val_c: Real) :Integer;
var
    max_n: Integer;
begin
    max_n := 0;

    if val_b > val_a then
    begin
        val_a := val_b;
        max_n := 1;
    end;

    if val_c > val_a then
        max_n := 2;

    sub_get_max := max_n;
end;

// Получение номера минимальной биссектрисы
function TDATriangle.get_bisc_min() :Integer;
var
    len_f, len_s, len_t: Real;
begin
    len_f := get_bisc_len(0);
    len_s := get_bisc_len(1);
    len_t := get_bisc_len(2);
    get_bisc_min := sub_get_min(len_f, len_s, len_t);
end;

end.

